package top.blueShark.template.controller;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import top.blueShark.template.entity.dto.LoginRequest;
import top.blueShark.template.entity.dto.PhoneRegisterRequest;
import top.blueShark.template.entity.SysUser;
import top.blueShark.template.service.SysUserService;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/auth")
public class AuthController {
    private static final Logger logger = LoggerFactory.getLogger(AuthController.class);


    private final SysUserService sysUserService;
    private final StringRedisTemplate redisTemplate;

    public AuthController(SysUserService sysUserService, StringRedisTemplate redisTemplate) {
        this.sysUserService = sysUserService;
        this.redisTemplate = redisTemplate;
    }


    /**
     * TODO 加密
     *  合并账号密码登录-登录
     *
     * @param req          登录请求体
     * @param req（username） 登录用户名（手机号码）
     * @param req（password） 登录密码
     * @param req（code）     登录验证码
     * @param req（type）     登录类型（ 1 : 账号登录、2 :验证码登录 ）
     */
    @PostMapping("/login")
    public Map<String, Object> login(@RequestBody LoginRequest req) {
        Map<String, Object> result = new HashMap<>();
        try {
            if (1 == req.getType()) {
                logger.info("密码登录：手机号码：{} : 密码：{}", req.getUsername(), req.getPassword());
                // 查询用户
                SysUser user = sysUserService.findByUsername(req.getUsername());
                /**
                 *   TODO @验证 用户存在性 和 密码 MD5 加密校验
                 *   req.getPassword().equals(user.getPassword())
                 */
                if (user == null || !SaSecureUtil.md5(req.getPassword()).equals(user.getPassword())) {
                    throw new RuntimeException("用户名或密码错误");
                }

                // 登录
                StpUtil.login(user.getId());

                // 获取用户的真实角色列表
                List<String> userRoles = sysUserService.getRoleNamesByUserId(user.getId());

                Map<String, Object> data = new HashMap<>();
                data.put("id", user.getId());
                data.put("username", user.getUsername());
                data.put("realName", user.getRealName());
                data.put("roles", userRoles); // 使用真实角色
                data.put("accessToken", StpUtil.getTokenValue());

                result.put("code", 0);
                result.put("data", data);
                result.put("error", null);
                result.put("message", "登录成功");
                return result;

            } else if (2 == req.getType()) {
                logger.info("验证码登录：手机号码：{} : 验证码：{}", req.getUsername(), req.getCode());
                // TODO 1. 校验验证码
                String cacheKey = "sms:login:code:" + req.getUsername();
                String codeInRedis = redisTemplate.opsForValue().get(cacheKey);
                if ("".equals(codeInRedis) || !codeInRedis.equals(req.getCode())) {
                    throw new RuntimeException("验证码错误或已过期");
                }
                // 2. 查询用户
                SysUser user = sysUserService.findByPhone(req.getUsername());
                if (user == null) {
                    throw new RuntimeException("用户不存在");
                }
                // 3. 登录
                StpUtil.login(user.getId());
                // 登录成功后，删除验证码
                redisTemplate.delete("sms:login:code:" + req.getUsername());

                // 获取用户的真实角色列表
                List<String> userRoles = sysUserService.getRoleNamesByUserId(user.getId());

                Map<String, Object> data = new HashMap<>();
                data.put("id", user.getId());
                data.put("username", user.getUsername());
                data.put("realName", user.getRealName());
                data.put("roles", userRoles); // 使用真实角色
                data.put("accessToken", StpUtil.getTokenValue());
                result.put("code", 0);
                result.put("data", data);
                result.put("error", null);
                result.put("message", "登录成功");
            } else {
                throw new RuntimeException("非法登录方式！");
            }
        } catch (Exception e) {
            result.put("code", 1);
            result.put("data", null);
            result.put("error", e.getMessage());
            result.put("message", "登录失败");
        }
        return result;
    }
    /**
     * 获取用户权限码列表【根据用户角色】
     * TODO 案例：[admin:"AC_100100", producer:"AC_100110", user:"AC_100120", "AC_100010"]
     *      前端配置：<!-- 需要指明 type="code" -->
     *              <AccessControl :codes="['AC_100100']" type="code">
     *                <Button> Super 账号可见 ["AC_1000001"] </Button>
     *              </AccessControl>
     *              <AccessControl :codes="['AC_100030']" type="code">
     *                <Button> Admin 账号可见 ["AC_100010"] </Button>
     *              </AccessControl>
     *  【在某些情况下，我们需要对按钮进行细粒度的控制，我们可以借助接口或者角色来控制按钮的显示】
     * */
    @GetMapping("/codes")
    public Map<String, Object> getCodes() {

        logger.info("getCodes");
        // 模拟权限码列表
        //List<String> codes = Arrays.asList("AC_100100", "AC_100110", "AC_100120", "AC_100010");

        Map<String, Object> result = new HashMap<>();
        result.put("code", 0);
        //result.put("data", codes);
        result.put("error", null);
        result.put("message", "ok");
        return result;
    }

    @PostMapping("/logout")
    public Map<String, Object> logout() {

        // 调用 sa-token 退出登录
        StpUtil.logout();

        Map<String, Object> result = new HashMap<>();
        result.put("code", 0);
        result.put("data", "");
        result.put("error", null);
        result.put("message", "ok");
        return result;
    }

    // TODO 注册API 使用 短信注册
    @PostMapping("/register")
    public Map<String, Object> register(@RequestBody PhoneRegisterRequest req) {

        System.out.println(req);
        Map<String, Object> result = new HashMap<>();
        try {
            // TODO 1. 校验验证码
//            String cacheKey = "sms:register:code:" + req.getPhone();
//            String codeInRedis = redisTemplate.opsForValue().get(cacheKey);
//            if ( "".equals(codeInRedis) || !codeInRedis.equals(req.getCode())) {
//                throw new RuntimeException("验证码错误或已过期");
//            }
            // 2. 检查手机号是否已注册
            SysUser existingUser = sysUserService.findByPhone(req.getPhone());
            if (existingUser != null) {
                throw new RuntimeException("手机号已注册");
            }
            // 3. 注册新用户
            SysUser user = new SysUser();
            user.setUsername(req.getPhone());
            user.setPhone(req.getPhone());

            //TODO md5加密
            user.setPassword(SaSecureUtil.md5(req.getPassword()));

            user.setRealName(req.getPhone());
            user.setStatus(1);
            user.setCreateTime(java.time.LocalDateTime.now());
            user.setUpdateTime(java.time.LocalDateTime.now());
            SysUser newUser = sysUserService.register(user);
            StpUtil.login(newUser.getId());


            // 注册成功后，删除验证码
            redisTemplate.delete("sms:register:code:" + req.getPhone());

            // 获取新注册用户的真实角色列表
            List<String> newUserRoles = sysUserService.getRoleNamesByUserId(newUser.getId());

            Map<String, Object> data = new HashMap<>();
            data.put("id", newUser.getId());
            data.put("username", newUser.getUsername());
            data.put("realName", newUser.getRealName());
            data.put("roles", newUserRoles); // 使用真实角色
            data.put("accessToken", StpUtil.getTokenValue());
            result.put("code", 0);
            result.put("data", data);
            result.put("error", null);
            result.put("message", "注册成功");
        } catch (Exception e) {
            result.put("code", 1);
            result.put("data", null);
            result.put("error", e.getMessage());
            result.put("message", "注册失败");
        }
        return result;
    }
}

